package c2.group.business.teampvp.sub;

import c2.group.business.base.GroupSubModule;
import c2.group.business.teampvp.*;
import cate.common.util.GameResult;
import cate.game.play.part.PlaySide;
import cp.solution.util.collection.ListKit;
import cp.solution.util.concurrent.ThreadFactoryImpl;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;

import java.util.*;
import java.util.concurrent.*;

@Slf4j
public class TeamPvpFightModule extends GroupSubModule<TeamPvpModule> {
    private final Map<String, TeamPvpFightTask> singleDogTask = new ConcurrentHashMap<>();
    private final Map<String, TeamPvpFightTask> teamTask = new ConcurrentHashMap<>();
    private final ExecutorService fightTaskExecutor = new ThreadPoolExecutor(1, 1,
            0L, TimeUnit.MILLISECONDS,
            new LinkedBlockingQueue<>(), new ThreadFactoryImpl("tp-fight-thread"));

    private final Object taskLock = new Object();

    public void settle() {
        synchronized (taskLock) {
            singleDogTask.clear();
            teamTask.clear();
            try{
                ((ThreadPoolExecutor)fightTaskExecutor).getQueue().clear();
            } catch (Exception e) {
                //
            }
        }
    }

    @Override
    public void onInterval() {
        synchronized (taskLock) {
            long start = System.currentTimeMillis();
            Iterator<Map.Entry<String, TeamPvpFightTask>> singleDogItr = singleDogTask.entrySet().iterator();
            while (singleDogItr.hasNext()) {
                Map.Entry<String, TeamPvpFightTask> entry = singleDogItr.next();
                TeamPvpFightTask task = entry.getValue();
                if (task.isMatchOver()) {
                    submitTask(task);
                }
                if (task.isFightOver()) {
                    singleDogItr.remove();
                }
            }
            Iterator<Map.Entry<String, TeamPvpFightTask>> teamTaskItr = teamTask.entrySet().iterator();
            while (teamTaskItr.hasNext()) {
                Map.Entry<String, TeamPvpFightTask> entry = teamTaskItr.next();
                TeamPvpFightTask task = entry.getValue();
                if (task.isMatchOver()) {
                    submitTask(task);
                }
                if (task.isFightOver()) {
                    teamTaskItr.remove();
                }
            }
            long cost = System.currentTimeMillis() - start;
            if (cost > 1000) {
                log.info("组队竞技战斗模块定时任务耗时过久，共{}个task, cost={}ms", singleDogTask.size() + teamTask.size(), cost);
            }
        }
    }

    private void submitTask(TeamPvpFightTask task) {
        fightTaskExecutor.submit(new TeamPvpFightRunnableTask(
                context.api.openApi(),
                context.fightHandler,
                task,
                context.play.getPlayBuildContext(),
                (report -> {
                    parent.afterChallenge(report);
                })));
    }

    public GameResult<Void> beginToFight(String playerUid, String teamUid) {
        GameResult<Void> r = new GameResult<>();
        synchronized (taskLock) {
            TeamPvpFightTask fightTask = findTask(teamUid, playerUid);
            if (fightTask == null) {
                return r.fail("您的战斗消失拉");
            }
            if (!StringUtils.equals(fightTask.challengerUid, playerUid)) {
                return r.fail("这场战斗可不是您的噢");
            }
            if (fightTask.isFighting()) {
                return r.fail("您的战斗已经开始了，请稍等");
            }
            submitTask(fightTask);
        }
        return r;
    }

    public TeamPvpFightTask findTask(String teamUid, String playerUid) {
        TeamPvpFightTask fightTask;
        synchronized (taskLock) {
            fightTask = singleDogTask.get(playerUid);
            if (fightTask != null) {
                return fightTask;
            }
            if (StringUtils.isBlank(teamUid)) {
                return null;
            }
            return teamTask.get(teamUid);
        }
    }

    public TeamPvpFightTask addTask(String challengerUid,
                                    String leaderUid,
                                    long preScore,
                                    byte type, String teamUid, List<TeamPvpPlayer> ateam, List<TeamPvpPlayer> bteam) {
        synchronized (taskLock) {
            TeamPvpFightTask fightTask = findTask(teamUid, ateam.get(0).ps.snapshot.uid);
            if (fightTask == null) {
                fightTask = new TeamPvpFightTask(challengerUid, leaderUid, preScore,
                        type, ateam, bteam);
                if (type == 1) {
                    singleDogTask.put(ateam.get(0).ps.snapshot.uid, fightTask);
                } else {
                    teamTask.put(teamUid, fightTask);
                }
            }
            return fightTask;
        }
    }

    public TeamPvpFightTask refreshTask(String teamUid, String playerUid, List<TeamPvpPlayer> ateam, List<TeamPvpPlayer> bteam) {
        synchronized (taskLock) {
            TeamPvpFightTask task = findTask(teamUid, playerUid);
            if (task == null) {
                return null;
            }
            task.refresh(ListKit.cloneList(ateam, TeamPvpPlayer::copy), ListKit.cloneList(bteam, TeamPvpPlayer::copy));
            return task;
        }
    }

    public GameResult<TeamPvpFightTask> updateTaskPos(String playerUid, String teamUid, List<String> newUids) {
        GameResult<TeamPvpFightTask> r = new GameResult<>();
        synchronized (taskLock) {
            TeamPvpFightTask task = findTask(teamUid, playerUid);
            if (task == null) {
                return r.fail("您的挑战已经开始拉");
            }
            if (System.currentTimeMillis() >= task.positionEndTime) {
                return r.fail("调整阶段已经过拉");
            }
            task.updatePos(newUids);
            r.data = task;
        }
        return r;
    }

    public TeamPvpFightTask savePosition(String playerUid, String teamUid, PlaySide ps) {
        synchronized (taskLock) {
            TeamPvpFightTask task = findTask(teamUid, playerUid);
            if (task == null) {
                return null;
            }
            if (System.currentTimeMillis() <= task.matchEndTime || System.currentTimeMillis() >= task.positionEndTime) {
                return null;
            }
            task.savePosition(ps);
            return task;
        }
    }

    public TeamPvpFightTask aheadToPosition(String playerUid, String teamUid) {
        synchronized (taskLock) {
            TeamPvpFightTask task = findTask(teamUid, playerUid);
            if (task == null) {
                return null;
            }
            if (System.currentTimeMillis() >= task.matchEndTime) {
                return null;
            }
            task.aheadToPosition();
            return task;
        }
    }

    public GameResult<Void> canMatching(String playerUid, String teamUid) {
        GameResult<Void> r = new GameResult<>();
        synchronized (taskLock) {
            TeamPvpFightTask task = findTask(teamUid, playerUid);
            if (task == null) {
                return r.fail("您未在匹配中");
            }
            if (System.currentTimeMillis() >= task.matchEndTime) {
                return r.fail("匹配阶段已经过拉");
            }
            if (task.refreshTimes >= 3) {
                return r.fail("您的刷新次数不足");
            }
            if (!StringUtils.equals(task.challengerUid, playerUid)) {
                return r.fail("这场战斗可不是您的噢");
            }
            return r;
        }
    }

    public boolean isFighting(String playerUid, String teamUid) {
        if (StringUtils.isBlank(playerUid)) {
            return false;
        }
        if (StringUtils.isNotBlank(teamUid)) {
            return teamTask.containsKey(teamUid);
        }
        return singleDogTask.containsKey(playerUid);
    }

    @Override
    public void onShutdown() {
        synchronized (taskLock) {
            Iterator<Map.Entry<String, TeamPvpFightTask>> singleDogItr = singleDogTask.entrySet().iterator();
            while (singleDogItr.hasNext()) {
                Map.Entry<String, TeamPvpFightTask> entry = singleDogItr.next();
                TeamPvpFightTask task = entry.getValue();
                if (!task.isFightOver()) {
                    new TeamPvpFightRunnableTask(
                            context.api.openApi(),
                            context.fightHandler,
                            task,
                            context.play.getPlayBuildContext(),
                            (report -> {
                                parent.afterChallenge(report);
                            })).run();
                    singleDogItr.remove();
                }
            }
            Iterator<Map.Entry<String, TeamPvpFightTask>> teamTaskItr = teamTask.entrySet().iterator();
            while (teamTaskItr.hasNext()) {
                Map.Entry<String, TeamPvpFightTask> entry = teamTaskItr.next();
                TeamPvpFightTask task = entry.getValue();
                if (!task.isMatchOver()) {
                    new TeamPvpFightRunnableTask(
                            context.api.openApi(),
                            context.fightHandler,
                            task,
                            context.play.getPlayBuildContext(),
                            (report -> {
                                parent.afterChallenge(report);
                            })).run();
                    teamTaskItr.remove();
                }
            }
        }
    }
}
